package com.emotion.recognition.server;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileItemFactory;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;

import com.emotion.recognition.shared.Constants;
import com.google.common.base.Preconditions;

@SuppressWarnings("serial")
public class FileUploadService extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException,
            IOException {
        super.doGet(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        if (ServletFileUpload.isMultipartContent(req)) {
            FileItemFactory factory = new DiskFileItemFactory();
            ServletFileUpload upload = new ServletFileUpload(factory);

            // Clear the images directory
            File imgDir = new File(getServletContext().getRealPath(Constants.IMAGES_DIRECTORY));
            if (imgDir.exists()) {
                for (File f : imgDir.listFiles()) {
                    if (f.isDirectory()) {
                        FileUtils.deleteDirectory(imgDir);
                    }
                }
            }

            // Create directories
            File zipDir = new File(getServletContext().getRealPath(Constants.ZIP_DIRECTORY));
            if (!zipDir.exists()) {
                zipDir.mkdirs();
            }
            File testDir = new File(getServletContext().getRealPath(Constants.TESTING_DIRECTORY));
            if (!testDir.exists()) {
                testDir.mkdirs();
            }
            File trainDir = new File(getServletContext().getRealPath(Constants.TRAINING_DIRECTORY));
            if (!trainDir.exists()) {
                trainDir.mkdirs();
            }

            try {
                @SuppressWarnings("unchecked")
                List<FileItem> items = upload.parseRequest(req);
                String fileNames = "";
                boolean training = true;
                for (FileItem item : items) {
                    if (item.isFormField())
                        continue;

                    Preconditions.checkArgument(item.getName() != null && item.getName() != "",
                            "Two items should be uploaded");

                    // Save the file into a folder.
                    String fileName = FilenameUtils.getName(item.getName());
                    File uploadedFile = new File(getServletContext().getRealPath(
                            Constants.ZIP_DIRECTORY), fileName);
                    item.write(uploadedFile);

                    // Unzip file and save images.
                    byte[] buf = new byte[1024];
                    ZipInputStream inputStream = new ZipInputStream(new FileInputStream(
                            uploadedFile));

                    ZipEntry entry = inputStream.getNextEntry();
                    while (entry != null) {
                        String entryName = entry.getName();
                        FileOutputStream outputStream = new FileOutputStream(
                                (training ? getServletContext().getRealPath(
                                        Constants.TRAINING_DIRECTORY) : getServletContext()
                                        .getRealPath(Constants.TESTING_DIRECTORY))
                                        + "/"
                                        + entryName);
                        int n;
                        while ((n = inputStream.read(buf, 0, 1024)) > -1) {
                            outputStream.write(buf, 0, n);
                        }
                        outputStream.close();
                        inputStream.closeEntry();
                        entry = inputStream.getNextEntry();
                    }
                    inputStream.close();

                    // After the first zip is uploaded, assume that testing zip comes next. This
                    // should be a safe assumption to make.
                    training = false;
                }

                // Create a string of file names delimited by commas. The training and testing set
                // are delimited by semi colons.
                File folder = new File(Constants.TESTING_DIRECTORY);
                File[] testingFiles = folder.listFiles();
                Arrays.sort(testingFiles);

                folder = new File(Constants.TRAINING_DIRECTORY);
                File[] trainingFiles = folder.listFiles();
                Arrays.sort(trainingFiles);

                for (int i = 0; i < trainingFiles.length; ++i) {
                    fileNames += trainingFiles[i].getName() + ",";
                }
                fileNames = fileNames.substring(0, fileNames.length() - 1) + ";";
                for (int i = 0; i < testingFiles.length; ++i) {
                    fileNames += testingFiles[i].getName() + ",";
                }
                fileNames = fileNames.substring(0, fileNames.length() - 1);

                System.out.println("DEBUG: The filenames are: " + fileNames);

                resp.setStatus(HttpServletResponse.SC_CREATED);
                resp.setContentType("text/html");
                resp.getWriter().print(fileNames);
                resp.flushBuffer();
            } catch (Exception e) {
                e.printStackTrace();
                resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
                        "An error occurred while creating the file : " + e.getMessage());
            }

        } else {
            resp.sendError(HttpServletResponse.SC_UNSUPPORTED_MEDIA_TYPE,
                    "Request contents type is not supported by the servlet.");
        }
    }
}
